﻿using common.attributes;
using common.components;
using common.data.helpers;
using common.enums;
using common.helpers;
using common.img.helpers;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Text;
using udm.localdb.helpers;

namespace img.mgr
{
    public class ImgMgrHelper
    {
        private readonly string _dbFile;

        private readonly string _connStr;

        public ImgMgrHelper(string dbFile)
        {
            _dbFile = dbFile;
            _connStr = $"Data Source={_dbFile};Version=3;";
        }

        public void Init()
        {
            if (!File.Exists(_dbFile))
            {
                var _defaultQuery = new SqliteHelper(_connStr);
                _defaultQuery.CreateDb();
                _defaultQuery.CreateTable<t_img>();
            }
        }

        public void Scan(ScanRequest request)
        {
            var level = 1;
            var directories = new List<string>
            {
                Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
                Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),"Download")
            };
            foreach (var directory in directories)
            {
                FindImg(directory, request, ref level);
            }
            //var drives = Directory.GetLogicalDrives();
            //foreach (var drive in drives)
            //{
            //    FindImg(drive, request, ref level);
            //}
        }

        private void FindImg(string topDirectory, ScanRequest request, ref int level)
        {
            var files = Directory.GetFiles(topDirectory, "*.*", SearchOption.TopDirectoryOnly);
            if (files.Length > 0)
            {
                var imgs = new List<t_img>();
                foreach (var file in files)
                {
                    var ext = Path.GetExtension(file);
                    if (string.IsNullOrEmpty(request.Exts) || request.Exts.IndexOf(ext.ToLower()) < 0)
                    {
                        continue;
                    }

                    //太小的图片不要
                    var fi = new FileInfo(file);
                    if (fi.Length < request.MinFileLength)
                    {
                        continue;
                    }

                    var img = new t_img
                    {
                        FullName = file,
                        FileName = fi.Name,
                        FileLength = fi.Length,
                        Level = level,
                        UpdateStatus = (int)UpdateStatusEnum.Ready,
                        CreateTime = fi.CreationTimeUtc.AddHours(8)
                    };
                    if (fi.Directory != null)
                    {
                        img.ParentFullName = fi.Directory.FullName;
                        img.ParentFileName = fi.Directory.Name;
                    }
                    imgs.Add(img);
                }

                if (imgs.Count > 0)
                {
                    SyncImg2Db(imgs, 1000);
                }
            }

            var directories = Directory.GetDirectories(topDirectory, "*", SearchOption.TopDirectoryOnly);
            if (directories.Length > 0)
            {
                level += 1;
                foreach (var directory in directories)
                {
                    if (directory.Contains("$Recycle.Bin"))
                    {
                        continue;
                    }
                    FindImg(directory, request, ref level);
                }
            }
        }

        private void SyncImg2Db(List<t_img> imgs, int capacity)
        {
            var defaultQuery = new SqliteHelper(_connStr);
            var groups = CollectionHelper.GetGroups<t_img>(imgs, capacity);
            foreach (var key in groups.Keys)
            {
                var sb = new StringBuilder();
                var dict = new Dictionary<string, object>();
                var ids = groups[key].Select(o => o.FullName).ToList();
                var sql = $"select FullName from t_img where FullName in ('{string.Join("','", ids)}')";
                var imgs_exists = defaultQuery.GetList<string>(sql);
                var imgs_add = imgs.Where(w => !imgs_exists.Contains(w.FullName)).ToList();
                if (imgs_add.Count > 0)
                {
                    for (var i = 0; i < imgs_add.Count; i++)
                    {
                        var img = imgs_add[i];
                        sb.AppendLine($"insert into t_img(FullName,FileName,ParentFullName,ParentFileName,FileLength,Level,CreateTime,UpdateStatus) values(@FullName_{i},@FileName_{i},@ParentFullName_{i},@ParentFileName_{i},{img.FileLength},{img.Level},'{img.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")}',{(int)UpdateStatusEnum.Ready});");
                        dict[$"FullName_{i}"] = img.FullName;
                        dict[$"FileName_{i}"] = img.FileName;
                        dict[$"ParentFullName_{i}"] = img.ParentFullName;
                        dict[$"ParentFileName_{i}"] = img.ParentFileName;
                    }
                    sql = sb.ToString();
                    defaultQuery.ExecuteNonQuery(sql, dict);
                }
                var imgs_update = imgs.Where(w => imgs_exists.Contains(w.FullName)).ToList();
                if (imgs_update.Count > 0)
                {
                    dict.Clear();
                    for (var i = 0; i < imgs_update.Count; i++)
                    {
                        var img = imgs_update[i];
                        sb.AppendLine($"update t_img set FileLength={img.FileLength} where FullName=@FullName_{i};");
                        dict[$"FullName_{i}"] = img.FullName;
                    }
                    sql = sb.ToString();
                    defaultQuery.ExecuteNonQuery(sql, dict);
                }
            }
        }

        public void UpdateImgInfo(int take = 50)
        {
            var sql = $"select FullName from t_img where UpdateStatus={(int)UpdateStatusEnum.Ready} limit {take}";
            var imgs = new SqliteHelper(_connStr).GetList<t_img>(sql);
            if (imgs.Count == 0)
            {
                return;
            }

            var ids = imgs.Select(o => o.FullName).ToList();
            UpdateStatus(UpdateStatusEnum.Updating, ids);

            var sb = new StringBuilder();
            var dict = new Dictionary<string, object>();
            for (var i = 0; i < imgs.Count; i++)
            {
                var img = imgs[i];
                var bytes = File.ReadAllBytes(img.FullName);
                img.MD5 = SecurityHelper.GetMD5String(bytes);

                var imgInfo = ImgHelper.Info(img.FullName);
                img.Width = imgInfo.Width;
                img.Height = imgInfo.Height;

                var rate = 0m;
                if (img.Height > 0)
                {
                    rate = Math.Floor(10.0m * img.Width / img.Height) / 10;
                }
                sb.AppendLine($"update t_img set MD5=@MD5_{i},Width={img.Width},Height={img.Height},Rate={rate},UpdateStatus={(int)UpdateStatusEnum.Success},UpdateTime='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' where FullName=@FullName_{i};");
                dict[$"FullName_{i}"] = img.FullName;
                dict[$"MD5_{i}"] = img.MD5;
            }
            sql = sb.ToString();
            new SqliteHelper(_connStr).ExecuteNonQuery(sql, dict);
        }

        private void UpdateStatus(UpdateStatusEnum status, List<string> ids)
        {
            var sql = $"update t_img set UpdateStatus={(int)status},UpdateTime='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' where FullName in ('{string.Join("','", ids)}')";
            new SqliteHelper(_connStr).ExecuteNonQuery(sql);
        }

        public List<GetDirectoriesResponseItem> GetDirectories(GetDirectoriesRequest request)
        {
            var dict = new Dictionary<string, object>();
            var filter = ParameterHelper.BuilderFilter<GetDirectoriesRequest>(dict, request);

            var sql = $"select ParentFullName FullName,ParentFileName FileName,Level,Count(*) Count from t_img {filter} GROUP BY ParentFullName";
            var items = new SqliteHelper(_connStr).GetList<GetDirectoriesResponseItem>(sql, dict);
            return items;
        }

        public TablePageResponse GetFiles(GetFilesRequest request)
        {
            var pagedList = new SqliteHelper(_connStr).GetPagedList<GetFilesRequest, GetImgsResponseItem>(request, "t_img", "*", "CreateTime,FullName,FileLength,Width,Height,Rate");
            for (var i = 0; i < pagedList.Items.Count; i++)
            {
                var item = pagedList.Items[i];
                item.createdat = item.createdat;
                if (string.IsNullOrEmpty(item.FullName))
                {
                    continue;
                }

                var token = SKHelper.GetFileToken(item.FullName, TimeSpan.FromSeconds(30 * (i + 1)));
                item.ViewFile = token;
            }
            return new TablePageResponse<GetImgsResponseItem>
            {
                rows = pagedList.Items,
                rc = pagedList.TotalCount
            };
        }

        [Table("t_img")]
        [Description("图片库")]
        public class t_img
        {
            /// <summary>
            /// 文件路径
            /// </summary>
            [Key]
            [MaxLength(500)]
            public string FullName { get; set; }

            /// <summary>
            /// 文件名
            /// </summary>
            [MaxLength(200)]

            public string FileName { get; set; }

            /// <summary>
            /// 上级路径
            /// </summary>
            [MaxLength(300)]
            public string ParentFullName { get; set; }

            /// <summary>
            /// 上级文件名
            /// </summary>
            [MaxLength(200)]
            public string ParentFileName { get; set; }

            /// <summary>
            /// 文件大小
            /// </summary>
            public long FileLength { get; set; }

            /// <summary>
            /// 层级
            /// </summary>
            public int Level { get; set; }

            /// <summary>
            /// MD5
            /// </summary>
            [MaxLength(100)]
            public string MD5 { get; set; }

            /// <summary>
            /// 宽
            /// </summary>
            public int Width { get; set; }

            /// <summary>
            /// 高
            /// </summary>
            public int Height { get; set; }

            /// <summary>
            /// 宽高比
            /// </summary>
            public decimal Rate { get; set; }

            /// <summary>
            /// 创建时间
            /// </summary>
            public DateTime CreateTime { get; set; }

            /// <summary>
            /// 修改状态
            /// </summary>
            public int UpdateStatus { get; set; }

            /// <summary>
            /// 修改时间
            /// </summary>
            public DateTime UpdateTime { get; set; }
        }
    }

    public class GetDirectoriesRequest
    {
        /// <summary>
        /// 文件名
        /// </summary>
        [AddIf(OperationType = AddIfOperationTypeEnum.Like)]

        public string FileName { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int64, OperationType = AddIfOperationTypeEnum.Range)]
        public string FileLength { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int32, OperationType = AddIfOperationTypeEnum.Range)]
        public string Width { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int32, OperationType = AddIfOperationTypeEnum.Range)]
        public string Height { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Decimal, OperationType = AddIfOperationTypeEnum.Range)]
        public string Rate { get; set; }
    }

    public class GetDirectoriesResponseItem
    {
        /// <summary>
        /// 文件路径
        /// </summary>
        public string FullName { get; set; }

        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// 数量
        /// </summary>
        public long Count { get; set; }
    }

    public class GetFilesRequest : DataPageRequest
    {
        /// <summary>
        /// 上级目录
        /// </summary>
        [AddIf]
        [Description("上级目录")]
        public string ParentFullName { get; set; }

        /// <summary>
        /// 文件名
        /// </summary>
        [AddIf(OperationType = AddIfOperationTypeEnum.Like)]

        public string FileName { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int64, OperationType = AddIfOperationTypeEnum.Range)]
        public string FileLength { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int32, OperationType = AddIfOperationTypeEnum.Range)]
        public string Width { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Int32, OperationType = AddIfOperationTypeEnum.Range)]
        public string Height { get; set; }

        [AddIf(FieldType = AddIfFieldTypeEnum.Decimal, OperationType = AddIfOperationTypeEnum.Range)]
        public string Rate { get; set; }
    }

    public class GetImgsResponseItem : DataPageResponseItemBase
    {
        /// <summary>
        /// 文件路径
        /// </summary>
        public string FullName { get; set; }

        /// <summary>
        /// 文件名
        /// </summary>

        public string FileName { get; set; }

        /// <summary>
        /// 上级路径
        /// </summary>
        public string ParentFullName { get; set; }

        /// <summary>
        /// 上级文件名
        /// </summary>
        public string ParentFileName { get; set; }

        /// <summary>
        /// 文件大小
        /// </summary>
        public long FileLength { get; set; }

        /// <summary>
        /// 层级
        /// </summary>
        public int Level { get; set; }

        /// <summary>
        /// MD5
        /// </summary>
        public string MD5 { get; set; }

        /// <summary>
        /// 宽
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// 高
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// 宽高比
        /// </summary>
        public decimal Rate { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateTime { get; set; }

        /// <summary>
        /// 修改状态
        /// </summary>
        public int UpdateStatus { get; set; }

        /// <summary>
        /// 修改时间
        /// </summary>
        public DateTime UpdateTime { get; set; }

        /// <summary>
        /// 查看文件
        /// </summary>
        public string ViewFile { get; set; }
    }

    public class ScanRequest
    {
        public string Exts { get; set; }

        public long MinFileLength { get; set; }
    }

    public class ImgViewRequest
    {
        public string FileName { get; set; }

        public string Token { get; set; }

        public int? Size { get; set; }
    }
}
